#ifndef DICCTRIE_H
#define DICCTRIE_H

#include <iostream>
#include <string>
#include "Nodo.h"
#include "ConjString.h" 
#include "String.h"

using namespace std;

template< class T >
class DiccTrie {
	
public:
	DiccTrie();
	T obtener( string clave ) const;
	void definir( string clave, T significado );
	bool esClave( string clave ) const;
	ConjString claves() const;
	void borrar(string clave);
	// Imprime el ConjString en pantalla en forma legible.
	//friend ostream & operator<<(ostream &o, const DiccTrie< T > &esp);

private:
	int indizar(const char &c) const{ return (int) c - 97; }
	void definirLetra( Nodo< T > **ptr, const char &c);
	
	Nodo< T > *raiz;
	ConjString *cClaves;
};

template< class T >
DiccTrie< T >::DiccTrie() {
	raiz = NULL;
	cClaves = new ConjString();
}

template< class T >
T DiccTrie< T >::obtener( string clave ) const{
	//precondicion: clave pertenece (claves(trie))
	
	Nodo<T> *ptr = raiz;
	
	if (raiz == NULL) cout << "No existe la clave";
	else {
		int i = 0;
		int indice;
		while (i < clave.length()){
			ptr->imprimir();
			indice = indizar(clave[i]);
			ptr = ptr->letras[indice];
			i++;
			ptr->imprimir();
		}
		
	}
	return ptr->dameValor();
}

template< class T >
void DiccTrie< T >::definir( string clave, T significado ){
	
	// precondicion:
	// long(clave) > 0 && (paratodo i en string) i pertenece ['a'..'z'];
	
	int i = 0;
	Nodo<T> *actual = new Nodo<T>();
	if (raiz == NULL){
		raiz = actual;
	}
	else{
		actual = raiz;	
	}
	while ( i < clave.length() ){
		
		if (!actual->esLetra(clave[i]) )
			
			this->definirLetra(&actual, clave[i]);
		
		actual = actual->letras[indizar(clave[i])];
		
		i++;
	}
	
	actual->hoja = true;
	actual->valor = new T(significado);
	
	//defino la clave en el conjunto de claves
	String s4(clave);
	cClaves->agregar(s4);
}


template< class T >
void DiccTrie< T >::definirLetra( Nodo< T > **ptr, const char &c ){
	
	int indice = indizar(c);
	
	if ( *ptr == NULL ){
		*ptr = new Nodo< T > ();
	}	

	(*ptr)->letras[indice] = new Nodo<T> ();
	
}

template< class T >
bool DiccTrie< T >::esClave( string clave ) const{
	Nodo< T > *ptr = raiz;
	if ( ptr == NULL ) {
		return false;
	}
	else{
		int i = 0;
		raiz->imprimir();
		while ( i < clave.length() && ptr->esLetra(clave[i]) ){
		
			ptr = ptr->letras[indizar(clave[i])];
			i++;
		}
		return ( i == clave.length() && ptr->esHoja() );
	}
}

template< class T >
ConjString DiccTrie< T >::claves( ) const{
	ConjString *conj;
	conj = cClaves;
	return ( *conj );
}

template< class T >
void DiccTrie< T >::borrar( string clave ){
	//ToDo: borrar del diccTrie
	
	String s4(clave);
	//borramos el elemento del conjunto de claves
	cClaves->eliminar( s4 );
}
/*
template< class T >
ostream &operator<<(ostream &o, const DiccTrie< T > &esp){
	//ToDo: hacer el operador recorriendo el trie para ver si esta bien definido el arbol
	
	//lo hago del modo facil recorrindo el conjunto de claves
	IteradorConjString *it;
	string elem;
	it = IteradorConjString(esp->claves());

	o << "Elementos del MultiConjuto : ";

	while ( it->tieneProximo() ) {
		elem = it->proximo();
		o << elem << ": " << esp->obtener(elem)<< endl;
	}
	return o;
}
*/
#endif
